#include "encrypt.h"

#include <ifaddrs.h>
#include <linux/if.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#include "libhtsc2.h"

#include "openssl/des.h"
#include "openssl/md5.h"
#include "openssl/pem.h"
#include "openssl/rsa.h"
#include "openssl/sha.h"

#define KEY_LENGTH 32

// unsigned char authKey[8];

// 获取设备mac地址
char *getLocalMacAddress();

// 获取设备IP
char *getLocalIP();

// 获取设备sn 码
unsigned char *getHtscSn();

// 设置加密芯片密码--默认
void setAuthKey(unsigned char *keys);

// 打开加密芯片
int openHtsc2(const unsigned char *keys);

// 读取加密芯片信息 ,默认从0位开始
int getHtsc2Data(const unsigned char *keys, unsigned char *data, unsigned int startAddr, unsigned int len);

// 修改加密芯片信息，默认从0位开始
int modifyHtsc2Data(const unsigned char *keys, unsigned const char *data, unsigned int startAddr, unsigned int len);

// 关闭加密芯片
void closeHtsc2();

// 获取设备cpu信息等
int getDeviceCpu(char *info);

// 数据异或处理--简单加密处理
void XORencryption(const unsigned *rawData, unsigned char *proceData, size_t len);

// 数据md5加密
void md5_encrypt(unsigned char *srcstr, unsigned char *encodedHexStr, int len);

// sha256加密
void sha256_encrypt(unsigned char *srcstr, size_t src_len, unsigned char *encodedHexStr);

// 辅助函数：将MAC地址字符串（如"00:0a:95:9d:68:16"）转换为6字节数组
void mac_str_to_bytes(const char *mac_str, unsigned char *mac_bytes)
{
    int values[6];
    sscanf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", &values[0], &values[1], &values[2], &values[3], &values[4],
           &values[5]);
    for (int i = 0; i < 6; ++i)
    {
        mac_bytes[i] = (unsigned char)values[i];
    }
}

// 辅助函数：将IP字符串（如"192.168.1.1"）转换为4字节数组
void ip_str_to_bytes(const char *ip_str, unsigned char *ip_bytes)
{
    int values[4];
    sscanf(ip_str, "%d.%d.%d.%d", &values[0], &values[1], &values[2], &values[3]);
    for (int i = 0; i < 4; ++i)
    {
        ip_bytes[i] = (unsigned char)values[i];
    }
}

// 将 MD5 加密
void md5_to_hex(unsigned char *md5, unsigned char *hex_str)
{
    for (int i = 0; i < MD5_DIGEST_LENGTH; i++)
    {
        sprintf((char *)&hex_str[i * 2], "%02x", (unsigned int)md5[i]);
    }
    hex_str[MD5_DIGEST_LENGTH * 2] = '\0';
}

void md5_encrypt(unsigned char *srcstr, unsigned char *encodedHexStr, int len)
{
    unsigned char digest[MD5_DIGEST_LENGTH];
    MD5_CTX ctx;
    MD5_Init(&ctx);
    // MD5_Update(&ctx, srcstr, strlen((unsigned char *)srcstr));
    MD5_Update(&ctx, srcstr, len);
    MD5_Final(digest, &ctx);
    md5_to_hex(digest, encodedHexStr);
}

// sha 256加密
//  将 SHA-256 哈希值转换为十六进制字符串（unsigned char 类型）
void sha256_to_hex(unsigned char *sha256, unsigned char *hex_str)
{
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        sprintf((char *)&hex_str[i * 2], "%02x", (unsigned int)sha256[i]);
    }
    hex_str[SHA256_DIGEST_LENGTH * 2] = '\0';
}

// 对 unsigned char 类型的字符串进行 SHA-256 加密并转换为十六进制字符串
void sha256_encrypt(unsigned char *srcstr, size_t src_len, unsigned char *encodedHexStr)
{
    unsigned char digest[SHA256_DIGEST_LENGTH];
    SHA256_CTX ctx;
    SHA256_Init(&ctx);
    SHA256_Update(&ctx, srcstr, src_len);
    SHA256_Final(digest, &ctx);

    sha256_to_hex(digest, encodedHexStr);
}

unsigned char *getHtscSn()
{
    unsigned char *sn = malloc(8);
    memset(sn, 0, 8);
    HTSC2_ReadSN(sn);
    return sn;
}

char *getLocalIP()
{
    struct ifaddrs *ifaddr, *ifa;
    int family;
    char host[NI_MAXHOST];
    char *result = NULL;

    if (getifaddrs(&ifaddr) == -1)
    {
        perror("getifaddrs");
        return NULL;
    }

    // 遍历所有网络接口
    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
    {
        if (ifa->ifa_addr == NULL)
            continue;

        family = ifa->ifa_addr->sa_family;

        // 检查 eth0 接口且是 IPv4 地址
        if (strcmp(ifa->ifa_name, "eth0") == 0 && family == AF_INET)
        {
            int s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
            if (s != 0)
            {
                fprintf(stderr, "getnameinfo() failed: %s\n", gai_strerror(s));
                continue;
            }

            // 分配内存并拷贝结果
            if ((result = malloc(strlen(host) + 1)) != NULL)
            {
                strcpy(result, host);
            }
            break;
        }
    }
    fprintf(stderr, "device ip : %s \n", result);
    freeifaddrs(ifaddr);
    return result;
}

char *getLocalMacAddress()
{
    FILE *file = fopen("/sys/class/net/eth0/address", "r");
    char *mac = NULL;
    char buffer[18]; // MAC地址长度固定为17字符+结束符

    if (file)
    {
        if (fgets(buffer, sizeof(buffer), file))
        {
            // 去除换行符
            buffer[strcspn(buffer, "\n")] = 0;

            // 分配内存并拷贝结果
            if ((mac = malloc(strlen(buffer) + 1)) != NULL)
            {
                strcpy(mac, buffer);
            }
        }
        fclose(file);
    }
    else
    {
        perror("fopen");
    }
    fprintf(stderr, "device mac : %s \n", mac);
    return mac;
}

void setAuthKey(unsigned char *keys)
{
    keys[0] = 'S'; // authkey为出厂默认密钥，请根据实际密钥修改
    keys[1] = 'Z';
    keys[2] = 'H';
    keys[3] = 'T';
    keys[4] = 'N';
    keys[5] = 'I';
    keys[6] = 'C';
    keys[7] = 'E';
}

int openHtsc2(const unsigned char *keys)
{
    int rst;
    if (HTSC2_Open())
    {
        printf("Open HTSC2 failed!\n");
        return 0;
    }
    // 使用默认密码或者新密码
    // setAuthKey(keys);

    rst = HTSC2_UserAuth(keys);
    if (rst)
    {
        printf("UserAuth ERROR: %d\n", rst);
        HTSC2_Close();
        return 0;
    }
    return 1;
}

int getHtsc2Data(const unsigned char *keys, unsigned char *data, unsigned int startAddr, unsigned int len)
{
    int rst;
    if (!keys)
        return 0;
    if (!data)
        return 0;
    if ((startAddr + len) < 64)
        return 0;
    memset(data, 0, 64);

    rst = HTSC2_ReadUserData(keys, startAddr, data, len);
    if (rst)
    {
        printf("ReadUserData ERROR: %d\n", rst);
        HTSC2_Close();
        return 0;
    }

    printf("Data read: ");
    for (int i = 0; i < len; i++)
        printf("%02X ", data[i]);
    printf("\n");
    return 1;
}

int modifyHtsc2Data(const unsigned char *keys, const unsigned char *data, unsigned int startAddr, unsigned int len)
{
    int rst;

    if (!keys)
        return 0;
    if (!data)
        return 0;
    if ((len + startAddr) > 64)
        return 0;

    printf("Data write: ");
    for (int i = 0; i < 64; i++)
        printf("%02X ", data[i]);
    printf("\n");

    rst = HTSC2_WriteUserData(keys, startAddr, data, len);
    if (rst)
    {
        printf("WriteUserData ERROR: %d\n", rst);
        HTSC2_Close();
        return 0;
    }
    return 1;
}

void closeHtsc2()
{
    HTSC2_Close();
}

// 检测设备密钥流程:
/*
1－获取加密芯片内容 64位
2－获取mac /ip 地址char 数据
3-上述数据预处理,大小端处理,拼接数据
4-openssl -sha加密 等--获取最终值,
5-获取某个文件内的密钥-两个char 数据比较 ,返回结果
*/

// 生成加密密钥
/*
1－获取加密芯片内容 64位
2－获取mac /ip 地址char 数据
3-上述数据预处理,大小端处理,拼接数据
4-openssl -sha加密 等--获取最终值,
5-将最终值保存在系统文件内
*/

// 加密
BinaryData encrypt()
{
    BinaryData result = {NULL, 0};
    // 加密芯片钥匙
    unsigned char key[8] = {0};
    // 加密数据
    unsigned char dataR[64] = {0};
    // 加密芯片sn码
    unsigned char *sn;

    setAuthKey(key);
    int rst = openHtsc2(key);
    if (!rst)
        return result;
    rst = getHtsc2Data(key, dataR, 0, 64);
    if (!rst)
        return result;

    sn = getHtscSn();
    closeHtsc2();

    char *ip = getLocalIP();
    if (!ip)
    {
        printf("IP error!!! ");
    }
    char *mac = getLocalMacAddress();
    if (!mac)
    {
        free(ip);
        printf("MAC error !!");
    }

    unsigned char mac_bytes[6] = {0};
    unsigned char ip_bytes[4] = {0};

    ip_str_to_bytes(ip, ip_bytes);
    mac_str_to_bytes(mac, mac_bytes);

    free(ip);
    free(mac);

    // 截止到这,全部数据已经集齐,,分别是key /dataR /mac_bytes /ip_bytes
    // 计算总数据长度：key(8) + dataR(64) + mac(6) + sn(8) = 86字节
    const int total_len = 8 + 64 + 6 + 8;
    unsigned char *all_data = malloc(total_len);
    memcpy(all_data, key, 8);
    memcpy(all_data + 8, dataR, 64);
    memcpy(all_data + 72, mac_bytes, 6);
    memcpy(all_data + 78, sn, 8);

    // 生成32字节的密钥（可根据需求调整长度）
    // md5 加密
    // unsigned char *final_key = malloc(MD5_DIGEST_LENGTH * 2 + 1);
    // memset(final_key, 0, MD5_DIGEST_LENGTH * 2 + 1);
    // md5_encrypt(all_data, final_key, total_len);

    // 异或校验
    // XORencryption(all_data, final_key, total_len); --这个数据的长度没影响--自定义

    // sha256加密  SHA256_DIGEST_LENGTH
    unsigned char *final_key = malloc(SHA256_DIGEST_LENGTH * 2 + 1);
    memset(final_key, 0, SHA256_DIGEST_LENGTH * 2 + 1);

    sha256_encrypt(all_data, total_len, final_key);
    printf("encode hex str :%s ", final_key);

    free(all_data);
    result.data = final_key;
    result.length = KEY_LENGTH;
    return result;
}

BinaryData getFileKey(const char *filename)
{
    BinaryData result = {NULL, 0};
    FILE *file = fopen(filename, "rb"); // 以二进制模式打开文件
    if (!file)
    {
        perror("文件打开失败");
        return result;
    }

    // 获取文件大小
    if (fseek(file, 0, SEEK_END) != 0)
    {
        perror("fseek 失败");
        fclose(file);
        return result;
    }

    long file_size = ftell(file);
    if (file_size == -1)
    {
        perror("ftell 失败");
        fclose(file);
        return result;
    }

    rewind(file); // 将文件指针重置到开头

    // 分配内存（不需要 +1，因为存储的是二进制数据）
    unsigned char *buffer = (unsigned char *)malloc(file_size);
    if (!buffer)
    {
        perror("内存分配失败");
        fclose(file);
        return result;
    }

    // 读取文件内容
    size_t bytes_read = fread(buffer, 1, file_size, file);
    if (bytes_read != (size_t)file_size)
    {
        perror("文件读取不完整");
        free(buffer);
        fclose(file);
        return result;
    }
    result.data = buffer;
    result.length = bytes_read;
    printf("encode hex str :%s ", buffer);
    fclose(file);
    return result;
}

int compareResult(BinaryData FinalKey, BinaryData fileKey)
{
    // 处理 NULL 指针的特殊情况
    if (FinalKey.data == NULL || fileKey.data == NULL)
        return 0;

    if (FinalKey.length != fileKey.length)
        return 0;
    int rst = (memcmp(FinalKey.data, fileKey.data, fileKey.length) == 0);
    free(FinalKey.data);
    free(fileKey.data);
    return rst;
}

int saveFinalKey(const char *filename, BinaryData FinalKey)
{
    FILE *file = fopen(filename, "wb"); // 二进制写入模式
    if (!file)
    {
        perror("文件打开失败");
        return 0;
    }
    if (!FinalKey.data)
    {
        return 0;
    }

    size_t bytes_written = fwrite(FinalKey.data, 1, FinalKey.length, file);
    fclose(file); // 无论成功与否都要关闭文件

    if (bytes_written != FinalKey.length)
    {
        fprintf(stderr, "写入不完整: %zu/%zu 字节\n", bytes_written, FinalKey.length);
        return 0;
    }
    free(FinalKey.data); // 手动释放传入进来的data 数据 --重要
    return 1;
}

int modHtsc2Data(const unsigned char *data)
{
    // 加密芯片钥匙
    unsigned char key[8] = {0};
    setAuthKey(key);
    int rst = openHtsc2(key);
    if (!rst)
        return 0;
    rst = modifyHtsc2Data(key, data, 0, 64);
    if (!rst)
        return 0;
    closeHtsc2();

    return 1;
}

void XORencryption(const unsigned *rawData, unsigned char *proceData, size_t len)
{
    if (!rawData || !proceData)
        return;

    // 循环异或处理：用所有数据影响密钥的每个字节
    for (int i = 0; i < len; ++i)
    {
        int key_idx = i % len;
        proceData[key_idx] ^= rawData[i];
        // 增加扰动：将当前字节与位置和上一个字节结合
        proceData[key_idx] = (proceData[key_idx] << 3) | (proceData[key_idx] >> 5);
        proceData[key_idx] += i;
    }
}
